package nf.translat;

import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import nf.translat.model.Reflection;
import nf.translat.model.db;
import nf.translat.model.excel;
import nf.translat.model.log;
import nf.translat.model.var;


/**
 * mysql数据库转换类
 * @author lishang
 */
public class MysqlTranslat {
    private String type; //来源类型 比如:dingxin
    public MysqlTranslat(String t){
        type=t;
    }
    
    //返回所有excel.tab名称或者说转换类型  
    public String[] getActions(){
        return new excel(type).tables();
    }
    
    /**
     * 执行转换过程 所有核心的操作的都在这个函数里 不过值得高兴地是它很短很简单
     * @param action 执行类型也就是excel中的工作表名  
    */
    public void run(String action){
        Parse.getInstance(type);   //解析类获取 根据类型  
        var config=Config(type);    //数据库链接的配置信息获取 通过类型 并初始化双方数据库  
        db.setInstance(type, config);   
        db.setInstance("nf",Config("nf"));
        var rows=getlines(action);   // excel中特定表的数据行数组形式返回  

        /**
         * all 所有需要转换的数据
         * fileds 所有需要转换的excel字段
         * toTablename转向后的表名
         */
        var all=new var(),fileds=new var(),toTabname=null;
        for(var line : rows){
            String[] col=line.toStrings();      //var数组类型 转换为 字符串数组类型  
            //根据列的数量 决定操作方式  
            switch (col.length){      
                case 0: //excel的一个同步任务执行 
                    if(all!=null && fileds==null) continue;
                    for(var row: all){
                        var toFileds=new var();
                        for(var f: fileds){
                            var key=f.get("to"),val=row.get(f.get("from"));
                            String parse=f.get("parse").toString();
                            if(parse!=null){
                                val=Parse.get(parse,f.get("from"),row,toFileds);
                            }
                            toFileds.set(key,val);
                        }
                        db.getInstance("nf").insert(toTabname.toString(),toFileds);
                    }
                    all.empyt();fileds.empyt();
                    break;
                case 1:  //1列作为描述信息  直接命令行显示  
                    log.Info(col[0]);
                    break;
                case 2:  //2列表示表名关系 从来源的数据库的那个表 到目的数据库的那个表 获取来源数据迭代器存放到all 获取目的表名到toTabname
                    all=db.getInstance(type).all(col[0]);
                    if(all.equals(false)) log.die("db get error");
                    toTabname=var.valueOf(col[1]);
                    break;
                case 3:  //3,4都表示字段关系  前两个字段为来源字段，目的字段  第3个是描述信息 4个是解析函数  字段信息统一写入的fileds
                case 4:
                default:
                    if(col[0].matches("^#") || col[1].isEmpty()) continue;
                    var filed= new var.dict("from", col[0], "to", col[1], "parse", null);
                    if(col.length==4) filed.set("parse",col[3]);
                    fileds.push(filed);
            }
        }
    }
    /**
     * 读取excel(type)文件的name工作表 返回数据  
     * @param name  工作表名  
     * @return 
     */
    private var getlines(String name){
        return new excel(type).read(name);
    }

    /**
     *  常用类型解析  
     *  默认值 ： 数字或"开始
     *  多行map:  给出的值作为map的入参 返回map值
     *  算数表达式： 字段名转换为值计算表达式的值返回
     *  扩展解析函数 必须集成parse类 
     */
    public static class  Parse{
        private static Parse Instance;
        public String bizCode="xxx";

        public static Parse getInstance(String name){
            try {
                String className=Parse.class.getPackage().getName()+"."+name.substring(0,1).toUpperCase() + name.substring(1) +"Parse";
                return Instance=(Parse)Class.forName(className).newInstance();                
            } catch (Exception ex) {
                Logger.getLogger(MysqlTranslat.class.getName()).log(Level.SEVERE, null, ex);
            }
            return Instance=new Parse();
        }
        
        /**
         * 解析类通用调用解析入口  
         */
        static var get(String name,var key,var row,var adds){
               var rt=(var)row.get(key);
               if(name.matches("^[\\d\\.]+$|^\\\"")){     //默认值字符串或数字
                   rt=var.valueOf(name);
               }else if(name.matches("\\n.+\\n")){        //多行map
                   var map=new var.dict(name);
                   rt=map.get(rt);
               }else if(name.matches("[\\+\\-*/`]+]")){            //字段操作 简单的算数运算表达式
                   if(name.matches("[\\w_]+")) {
                       Matcher m = Pattern.compile("`([\\w_]+)`").matcher(name);
                       while (m.find()) {
                           String k = m.group();
                           String v = row.get(k).toString();
                           name=name.replace(k, v);
                       }
                   }
                   rt= new var.expr(name);
               }else{
                   Reflection r=new Reflection(Instance);
                   if(r.method_exists(name))
                       rt=r.method_call(name,key.toString(),row,adds);
                   else
                       log.Info("丢弃处理："+name);
               }

               return rt;
        }
        ////常用解析函数 
        public var intime(String key,var row,var adds){
            var rt;
            Date Time = new Date();
            rt=var.valueOf(String.valueOf(Time.getTime()));
            return rt;
        }

        public var bizCode(String key,var row,var adds){
            return  var.valueOf(bizCode);
        }

        public var bizName(String key,var row,var adds){
            return var.valueOf("xxxx");
        }
    }
    /**
     * 配置信息需要接入现有系统 并进行数据返回  
     * @param type
     * @return 
     */
    var  Config(String type){
        var rt=null;
        if(type=="dingxin") return new var.list("192.168.31.161","cine","root","123456");
        return new var.list("192.168.31.161","nf","root","123456");
    }
    
    //小展示dome
    public static void  main(String[] arg){
        MysqlTranslat t = new MysqlTranslat("dingxin");
        String[] a = t.getActions();
        //输出类型  
        for(int i=0;i<a.length;i++)
            System.out.println(a[i]);
        
        //运行单独转换
        t.run("影院信息");
    }
    
}
